﻿using System;
using System.Drawing; // 确保项目引用 System.Drawing.Common (NuGet) 或使用如 ImageSharp
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
using System.Security.AccessControl; // For EventWaitHandleRights
using System.Security.Principal; // For SecurityIdentifier
using System.Text;
using System.Threading;
using System.Threading.Tasks;

// 与C++端共享的头部结构定义 (确保字段类型和顺序一致)
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SharedMemoryHeader
{
    public volatile uint imageActualSizeBytes;
    // 如果有其他元数据，也在这里定义
}

public class SharedMemoryImageReceiver : IDisposable
{
    // 从C++头文件同步这些名称
    private const string DefaultMMFName = "Global\\MyImageSharedMemory";
    private const string DefaultMutexName = "Global\\MyImageSharedMemoryMutex";
    private const string DefaultEventDataReadyName = "Global\\MyImageSharedMemoryDataReadyEvent";
    // private const string DefaultEventDataReadName = "Global\\MyImageSharedMemoryDataReadEvent"; // (可选)

    private MemoryMappedFile mmf;
    private MemoryMappedViewAccessor accessor;
    private Mutex mutex;
    private EventWaitHandle dataReadyEvent;
    // private EventWaitHandle dataReadEvent; // (可选)

    private bool isInitialized = false;
    private bool isDisposed = false;
    private uint mmfMaxSize = 0; // 用于记录MMF的预期大小，但实际大小由创建者决定

    public bool IsInitialized => isInitialized;

    public SharedMemoryImageReceiver()
    {
        if (Console.IsOutputRedirected == false)
        {
            try { Console.OutputEncoding = Encoding.UTF8; } catch { /*忽略*/ }
        }
    }

    // 方法：打开共享内存及同步对象
    // 参数: mmfName - 共享内存的名称
    // 参数: mutexName - 互斥锁名称
    // 参数: dataReadyEventName - 数据就绪事件名称
    // 返回: true 如果成功, false 如果失败
    // 对应GUI操作："连接到共享内存服务"按钮
    public bool Initialize(string mmfName = DefaultMMFName,
                           string mutexName = DefaultMutexName,
                           string dataReadyEventName = DefaultEventDataReadyName)
    {
        if (isInitialized)
        {
            Console.WriteLine("C# 接收端：已初始化，无需重复。");
            return true;
        }

        try
        {
            Console.WriteLine($"C# 接收端：正在尝试打开互斥锁 '{mutexName}'...");
            mutex = Mutex.OpenExisting(mutexName);
            Console.WriteLine("C# 接收端：互斥锁已打开。");

            Console.WriteLine($"C# 接收端：正在尝试打开事件 '{dataReadyEventName}'...");
            dataReadyEvent = EventWaitHandle.OpenExisting(dataReadyEventName);
            Console.WriteLine("C# 接收端：DataReady 事件已打开。");

            // (可选) 打开数据读取事件
            // dataReadEvent = EventWaitHandle.OpenExisting(dataReadEventName);

            Console.WriteLine($"C# 接收端：正在尝试打开内存映射文件 '{mmfName}'...");
            mmf = MemoryMappedFile.OpenExisting(mmfName, MemoryMappedFileRights.ReadWrite); // 需要读写权限来操作accessor, 即使只读数据
            Console.WriteLine("C# 接收端：内存映射文件已打开。");

            // 创建视图访问器，访问整个文件
            // mmf.CreateViewAccessor() 默认大小是MMF的实际大小
            accessor = mmf.CreateViewAccessor(0, 0, MemoryMappedFileAccess.ReadWrite); // offset 0, size 0 (entire MMF)
            Console.WriteLine("C# 接收端：内存映射文件视图已创建。");
            // 无法直接从OpenExisting获取创建时的大小，需要发送方告知或通过约定。
            // 这里假设发送方创建的MMF大小是固定的，或者发送方会在头部写入总大小信息（但我们例子中头部是图片实际大小）
            // mmfMaxSize = (uint)accessor.Capacity; // 获取实际映射的大小
            // Console.WriteLine($"C# 接收端：MMF 实际容量: {mmfMaxSize} 字节。");


            isInitialized = true;
            Console.WriteLine("C# 接收端：共享内存服务连接初始化成功。");
            return true;
        }
        catch (WaitHandleCannotBeOpenedException ex)
        {
            LogError($"打开同步对象失败 (可能未创建或名称错误): {ex.Message}");
        }
        catch (FileNotFoundException ex) // MMF 未找到
        {
            LogError($"打开内存映射文件失败 (可能未创建或名称错误): {ex.Message}");
        }
        catch (Exception ex)
        {
            LogError($"初始化时发生未知错误: {ex.Message}");
        }

        Close(); // 如果初始化部分失败，清理已打开的资源
        return false;
    }

    // 方法：异步等待数据并接收图像
    // 参数: timeoutMilliseconds - 等待数据就绪事件的超时时间
    // 返回: Task<Image> - 异步操作的结果，成功则为 Image 对象，失败则为 null
    // 对应GUI操作："接收图像"按钮 (内部会等待事件)
    public async Task<Image> ReceiveImageAsync(int timeoutMilliseconds = Timeout.Infinite)
    {
        if (!isInitialized)
        {
            LogError("服务未初始化，无法接收图像。");
            return null;
        }

        Console.WriteLine("C# 接收端：正在等待 DataReady 事件...");
        bool eventSignaled = await Task.Run(() => dataReadyEvent.WaitOne(timeoutMilliseconds)); // 在线程池等待事件

        if (!eventSignaled)
        {
            Console.WriteLine("C# 接收端：等待 DataReady 事件超时或失败。");
            return null;
        }
        Console.WriteLine("C# 接收端：DataReady 事件已收到。");

        Image receivedImage = null;
        Console.WriteLine("C# 接收端：正在尝试获取互斥锁...");
        bool mutexAcquired = false;
        try
        {
            mutexAcquired = mutex.WaitOne(timeoutMilliseconds > 0 ? timeoutMilliseconds : 5000); // 给获取互斥锁也设一个超时
            if (!mutexAcquired)
            {
                LogError("获取互斥锁超时。");
                return null;
            }
            Console.WriteLine("C# 接收端：已获取互斥锁。正在从共享内存读取数据...");

            SharedMemoryHeader header;
            accessor.Read(0, out header); // 从偏移量0读取头部

            uint imageSizeBytes = header.imageActualSizeBytes;
            Console.WriteLine($"C# 接收端：从头部读取到图像大小: {imageSizeBytes} 字节。");

            // 检查图像大小的合理性
            // accessor.Capacity 返回的是整个MMF视图的大小
            long mmfCapacity = accessor.Capacity;
            if (imageSizeBytes == 0 || imageSizeBytes > (mmfCapacity - Marshal.SizeOf<SharedMemoryHeader>()))
            {
                LogError($"读取到的图像大小无效 ({imageSizeBytes}) 或超出共享内存可容纳范围 (MMF容量: {mmfCapacity}字节)。");
                return null; // 在 finally 中释放互斥锁
            }

            byte[] imageData = new byte[imageSizeBytes];
            // 图像数据紧随头部之后
            accessor.ReadArray<byte>((long)Marshal.SizeOf<SharedMemoryHeader>(), imageData, 0, (int)imageSizeBytes);
            Console.WriteLine("C# 接收端：图像数据已从共享内存读取。");

            using (MemoryStream ms = new MemoryStream(imageData))
            {
                receivedImage = Image.FromStream(ms);
                Console.WriteLine("C# 接收端：图像对象已成功创建。");
            }

            // (可选) 通知发送方数据已读取
            // dataReadEvent?.Set(); 
            // Console.WriteLine("C# 接收端：已设置 DataRead 事件，通知发送方。");

        }
        catch (AbandonedMutexException ex)
        {
            LogError($"互斥锁被放弃 (可能发送端异常退出): {ex.Message}");
            // 互斥锁状态可能已损坏，最好重新初始化
            isInitialized = false; //标记为未初始化
        }
        catch (Exception ex)
        {
            LogError($"读取共享内存或创建图像时发生错误: {ex.Message}");
            return null; // 在 finally 中释放互斥锁
        }
        finally
        {
            if (mutexAcquired)
            {
                mutex.ReleaseMutex();
                Console.WriteLine("C# 接收端：已释放互斥锁。");
            }
        }
        return receivedImage;
    }


    // 方法：关闭所有句柄并释放资源
    // 对应GUI操作："断开连接"按钮或程序退出
    public void Close()
    {
        Console.WriteLine("C# 接收端：正在关闭资源...");
        isInitialized = false; // 标记为未初始化

        accessor?.Dispose();
        accessor = null;
        if (mmf != null)
        {
            try { mmf.Dispose(); } catch (Exception ex) { Console.WriteLine($"关闭MMF时出错: {ex.Message}"); }
            mmf = null;
            Console.WriteLine("C# 接收端：内存映射文件已释放。");
        }

        dataReadyEvent?.Dispose();
        dataReadyEvent = null;
        // dataReadEvent?.Dispose(); dataReadEvent = null;

        if (mutex != null)
        {
            try { mutex.Dispose(); } catch (Exception ex) { Console.WriteLine($"关闭Mutex时出错: {ex.Message}"); }
            mutex = null;
            Console.WriteLine("C# 接收端：同步对象已释放。");
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (isDisposed) return;
        if (disposing)
        {
            Close(); // 调用Close来释放所有资源
        }
        isDisposed = true;
    }
    ~SharedMemoryImageReceiver()
    {
        Dispose(false);
    }

    private void LogError(string message)
    {
        Console.WriteLine($"C# 接收端错误: {message}");
    }
}

// --- C# 端示例用法 (仅为演示如何调用) ---
/*
public class Program
{
    public static async Task Main(string[] args)
    {
        if (Console.IsOutputRedirected == false) { try { Console.OutputEncoding = System.Text.Encoding.UTF8; } catch { } }

        SharedMemoryImageReceiver receiver = new SharedMemoryImageReceiver();

        Console.WriteLine("[主程序 C#] 用户点击“连接共享内存服务”。");
        if (receiver.Initialize())
        {
            Console.WriteLine("[主程序 C#] 成功连接到共享内存服务。");

            Console.WriteLine("[主程序 C#] 用户点击“接收图像”（程序将等待数据就绪信号...）。");
            // 在GUI中，这可能是一个循环或者一个由外部触发的调用
            Image img = await receiver.ReceiveImageAsync(timeoutMilliseconds: 15000); // 等待15秒

            if (img != null)
            {
                Console.WriteLine("[主程序 C#] 成功接收到图像。");
                try
                {
                    string fileName = $"CSharp_MMF接收的图像_{DateTime.Now:yyyyMMdd_HHmmss}.png";
                    img.Save(fileName, System.Drawing.Imaging.ImageFormat.Png);
                    Console.WriteLine($"[主程序 C#] 图像已保存为: {fileName}");
                    img.Dispose();
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"[主程序 C#] 保存图像时出错: {ex.Message}");
                    img?.Dispose();
                }
            }
            else
            {
                Console.WriteLine("[主程序 C#] 未能接收到图像或超时。");
            }
        }
        else
        {
            Console.WriteLine("[主程序 C#] 连接到共享内存服务失败。请确保C++发送端已启动并创建了共享资源。");
        }

        Console.WriteLine("[主程序 C#] 用户点击“断开”或程序关闭。");
        receiver.Close(); // 或 receiver.Dispose();
        Console.WriteLine("[主程序 C#] 示例结束。按任意键退出。");
        if (!Console.IsInputRedirected) Console.ReadKey();
    }
}
*/